﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Model_SSResourceManager
{
    public class QueueManager
    {
        private readonly IDataBase _dataBase;

        internal QueueManager(IDataBase dataBase)
        {
            this._dataBase = dataBase;
        }

        public Queue Create(Guid idUser,Guid idResource)
        {
            return new Queue()
                       {
                           Id = Guid.NewGuid(),
                           IdUser = idUser,
                           IdResource = idResource
                       };
        }

        public bool Add(Queue queue)
        {
            if (queue.MessageTime == null)
            {
                var user = _dataBase.GetUser(queue.IdUser);
                if (user != null)
                {
                    queue.MessageTime = queue.StartTime - user.MessageTimeSpan;
                }
            }

            return _dataBase.AddQueue(queue);
        }

        public bool Update(Queue queue)
        {
            return _dataBase.UpdateQueue(queue);
        }

        public bool Delete(Guid id)
        {
            return _dataBase.DeleteQueue(id);
        }

        public Queue Get(Guid id)
        {
            return _dataBase.GetQueue(id);
        }

        public List<Queue> GetAll(bool onlyActive = false)
        {
            return _dataBase.GetAllQueue(onlyActive).OrderBy(queue => queue.StartTime).ToList();
        }

        public IEnumerable<Queue> GetAllForUser(Guid userId)
        {
            return this.GetAll(true).Where(queue => queue.IdUser == userId).OrderBy(queue => queue.StartTime);
        }

        public IEnumerable<Queue> GetAllForResource(Guid resourceId)
        {
            return this.GetAll(true).Where(queue => queue.IdResource == resourceId).OrderBy(queue => queue.StartTime);
        }

        public List<string[]> CheckAvaiable(Queue queue)
        {
            return CreateResultString(
                                            GetIntersectQueues(queue, GetAllForUser(queue.IdUser)),
                                            GetIntersectQueues(queue, GetAllForResource(queue.IdResource)) );
        }


        public string CreateNearBook(Guid resourceId, Guid userId)
        {
            Resource currentResource = _dataBase.GetResource(resourceId);
            List<Queue> resourceQueues = GetAllForResource(resourceId).ToList();
            IEnumerable<Queue> userQueues = GetAllForUser(userId);
            Queue nearQueue = Create(userId, resourceId);

            if (resourceQueues.Any())
            {
                nearQueue.StartTime = (DateTime) GetNearStartTime(resourceQueues, currentResource.TimeOfUsing);
                nearQueue.StartTime = nearQueue.StartTime.AddMinutes(5);
            }
            else
                nearQueue.StartTime = DateTime.Now;
            nearQueue.FinishTime = nearQueue.StartTime + currentResource.TimeOfUsing;

            var result = new StringBuilder("Sorry,but resources are fully busy or you already inlie in free time in other resource");

            if (nearQueue.FinishTime.TimeOfDay < currentResource.EndTime)
                if (CreateResultString(
                                   GetIntersectQueues(nearQueue, userQueues),
                                   GetIntersectQueues(nearQueue, resourceQueues))
                                       .First()[0] == "Available")
                {
                    result = new StringBuilder("You get in line between");
                    result.AppendFormat(" {0} and {1}", nearQueue.StartTime.TimeOfDay, nearQueue.FinishTime.TimeOfDay);
                    Add(nearQueue);
                }
            return result.ToString();
        }

        private DateTime? GetNearStartTime(List<Queue> resourceQueues,TimeSpan usingTime)
        {
            DateTime? startTime = null;

            for (int i = 0; i < resourceQueues.Count - 1; i++)
            {
                if ((resourceQueues[i + 1].StartTime - resourceQueues[i].FinishTime) > usingTime)
                {
                    startTime = resourceQueues[i].FinishTime;
                    break;
                }
            }

            return startTime ?? (startTime = resourceQueues.Last().FinishTime);
        }

        private IEnumerable<Queue> GetIntersectQueues(Queue newQueue, IEnumerable<Queue> queues)
        {
            return queues.Where(currentQueue =>
                                              (currentQueue.FinishTime >= newQueue.StartTime && 
                                               currentQueue.StartTime <= newQueue.FinishTime));
        }

        private List<string[]> CreateResultString(IEnumerable<Queue> intersectUserQueues, IEnumerable<Queue> intersectResourceQueues)
        {
            var resultString = new List<string[]>();

            if (intersectUserQueues.Any())
            {
                resultString.Add(new[] { "Warning", "You already in line on:" });

                resultString.AddRange(intersectUserQueues.Select(intersectUserQueue =>
                    new[] 
                                {
                                    _dataBase.GetResource(intersectUserQueue.IdResource).Name, 
                                    "between", 
                                    intersectUserQueue.StartTime.ToShortTimeString(),
                                    "and", 
                                    intersectUserQueue.FinishTime.ToShortTimeString()
                                }));
            }

            else if (intersectResourceQueues.Any())
            {
                resultString.Add(new[] { "Error", "This resource is already busy" });

                resultString.AddRange(intersectResourceQueues.Select(intersectResourceQueue =>
                    new[]
                                {
                                    "by",
                                    _dataBase.GetUser(intersectResourceQueue.IdResource).Login,
                                    "between", intersectResourceQueue.StartTime.ToShortTimeString(),
                                    "and",
                                    intersectResourceQueue.FinishTime.ToShortTimeString()
                                }));
            }

            else
            {
                resultString.Add(new[] { "Available" });
            }

            return resultString;
        }



      
    }
}
